/**
 * 用于javabean和xml之间的转换
 */
package com.zx.framework.core.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.beanutils.ConversionException;
import org.apache.log4j.Logger;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

public class XstreamUtil {

	private static final Logger LOGGER = Logger.getLogger(XstreamUtil.class);

	/**
	 * 将xml转换为bean
	 * 
	 * @param xml
	 * @param t
	 * @return
	 */
	public static <T> T xml2bean(String xml, Class<T> t) {
		return xml2bean(xml, t, null);
	}

	/**
	 * 将xml转换为bean
	 * 
	 * @param xml
	 * @param t
	 * @param alias
	 * @return
	 */
	public static <T> T xml2bean(String xml, Class<T> t, String alias) {
		XStream xstream = new XStream();
		xstream.registerConverter(new XstreamUtil.DateConverter());
		xstream.registerConverter(new XstreamUtil.DoubleConverter());
		xstream.ignoreUnknownElements();
		if (StringUtil.isNotEmpty(alias)) {
			xstream.alias(alias, t);
		}
		T rs = (T) xstream.fromXML(xml);
		return rs;
	}

    public static String bean2xml(Object bean ,Class<?> T, String alias){
        Map<Class,String> map = new HashMap<>();
        map.put(T,alias);
        return bean2xml(bean,map);
    }

    public static String bean2xml(Object bean,Map<Class,String> alias){
        XStream xstream = new XStream();
        xstream.registerConverter(new XstreamUtil.DateConverter());
        xstream.registerConverter(new XstreamUtil.DoubleConverter());
        if (null != alias) {
            for (Map.Entry<Class,String> entry : alias.entrySet()) {
                if (StringUtil.isNotBlank(entry.getValue())) {
                    xstream.alias(entry.getValue(), entry.getKey());
                }
            }
        }
        return xstream.toXML(bean);
    }

	public static class DateConverter implements Converter {

		@Override
		public boolean canConvert(Class arg0) {

			return Date.class == arg0;
		}

		@Override
		public void marshal(Object arg0, HierarchicalStreamWriter arg1,
				MarshallingContext arg2) {
            arg1.setValue(DatetimeUtils.dateToString((Date)arg0, "yyyy-MM-dd HH:mm:ss"));
		}

		@Override
		public Object unmarshal(HierarchicalStreamReader reader,
				UnmarshallingContext arg1) {
			if(StringUtil.isEmpty(reader.getValue())){
				return null;
			}
			GregorianCalendar calendar = new GregorianCalendar();
			SimpleDateFormat dateFm = new SimpleDateFormat("yyyy-MM-dd"); // 格式化当前系统日期
			SimpleDateFormat dateFm1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 格式化当前系统日期
			boolean can = false;
			try {
				calendar.setTime(dateFm1.parse(reader.getValue()));
				can = true;
			} catch (ParseException e) {
				
			}
			
			if (!can) {
				try {
					calendar.setTime(dateFm.parse(reader.getValue()));
					can = true;
				} catch (ParseException e) {
				}
			}

			if (!can) {
				throw new ConversionException("can not convert!");
			}
			return calendar.getTime();

		}
	}

	public static class DoubleConverter implements Converter {

		@Override
		public boolean canConvert(Class arg0) {

			return Double.class == arg0;
		}

		@Override
		public void marshal(Object arg0, HierarchicalStreamWriter arg1,
				MarshallingContext arg2) {
            arg1.setValue(ObjectUtils.getStringValue(arg0));
		}

		@Override
		public Object unmarshal(HierarchicalStreamReader reader,
				UnmarshallingContext arg1) {
			Double doublenum = null;
			if (StringUtil.isEmpty(reader.getValue())) {
				if(LOGGER.isDebugEnabled()){
					LOGGER.debug("doublenum is null");
				}
				
			} else {
				doublenum = Double.valueOf(reader.getValue());
				if(LOGGER.isDebugEnabled()){
					LOGGER.debug("doublenum is not null");
				}
			}
			return doublenum;
		}
	}
}
